package com.atguigu.gmall.payment.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import com.atguigu.gmall.enums.model.OrderStatus;
import com.atguigu.gmall.enums.model.PaymentStatus;
import com.atguigu.gmall.enums.model.PaymentType;
import com.atguigu.gmall.order.client.OrderFeignClient;
import com.atguigu.gmall.order.model.OrderInfo;
import com.atguigu.gmall.payment.config.AlipayConfig;
import com.atguigu.gmall.payment.model.PaymentInfo;
import com.atguigu.gmall.payment.service.AlipayService;
import com.atguigu.gmall.payment.service.PaymentInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Map;

/**
 * @author: atguigu
 * @create: 2023-03-14 10:36
 */
@Slf4j
@Service
public class AlipayServiceImpl implements AlipayService {

    @Autowired
    private OrderFeignClient orderFeignClient;

    @Autowired
    private PaymentInfoService paymentInfoService;


    @Autowired
    private AlipayClient alipayClient;


    /**
     * 展示支付宝支付表单页面
     *
     * @param orderId 订单ID
     * @return
     */
    @Override
    public String createAlipayForm(Long orderId, String userId) {
        try {
            //1.远程调用订单微服务获取订单信息
            OrderInfo orderInfo = orderFeignClient.getOrderInfo(orderId);
            if (orderInfo != null && OrderStatus.UNPAID.name().equals(orderInfo.getOrderStatus())) {
                //2.保存本地交易记录
                PaymentInfo paymentInfo = new PaymentInfo();
                //2.1 商家生成订单编号
                paymentInfo.setOutTradeNo(orderInfo.getOutTradeNo());
                paymentInfo.setOrderId(orderInfo.getId());
                paymentInfo.setUserId(Long.valueOf(userId));
                paymentInfo.setPaymentType(PaymentType.ALIPAY.name());
                //todo 为了开发方便将支付总金额本地设置0.01元
                paymentInfo.setTotalAmount(new BigDecimal("0.01"));
                paymentInfo.setPaymentStatus(PaymentStatus.UNPAID.name());
                //todo 支付宝回调结果;支付宝端交易编号 等用户支付成功后才会更新
                paymentInfoService.savePaymentInfo(paymentInfo, PaymentType.ALIPAY.name());

                //3.调用支付宝生成支付页面接口(PC电脑网站支付页请求对象)
                //AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();

                //3.调用支付宝生成支付页面接口(手机端支付页请求对象)
                AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
                //异步接收地址，仅支持http/https，公网可访问 提供给支付宝异步回调接口地址,通知商户端支付结果
                request.setNotifyUrl(AlipayConfig.notify_payment_url);
                //同步跳转地址，仅支持http/https  提供给支付宝同步回到支付结果,通知用户查看支付成功页面
                request.setReturnUrl(AlipayConfig.return_payment_url);
                /******必传参数******/
                JSONObject bizContent = new JSONObject();
                //商户订单号，商家自定义，保持唯一性
                bizContent.put("out_trade_no", orderInfo.getOutTradeNo());
                //支付金额，最小值0.01元
                bizContent.put("total_amount", 0.01);
                //订单标题，不可使用特殊符号
                bizContent.put("subject", orderInfo.getTradeBody());
                //电脑网站支付场景固定传值FAST_INSTANT_TRADE_PAY
                //bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
                //手机移动端支付场景固定传值
                bizContent.put("product_code", "QUICK_WAP_WAY");
                bizContent.put("timeout_express", "10m");
                request.setBizContent(bizContent.toString());
                //AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
                AlipayTradeWapPayResponse response = alipayClient.pageExecute(request);
                if (response.isSuccess()) {
                    //支付表单
                    return response.getBody();
                }
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            log.error("生成支付宝支付页面异常,订单ID:{},异常信息:{}", orderId.toString(), e);
        }
        return null;
    }


    /**
     * 支付宝进行异步回调,通知商家支付结果,修改本地交易记录状态
     * 1.业务校验
     * 2.处理支付成功后业务
     *
     * @param paramsMap 支付宝回调提交所有参数 通过get方法key获取对于值
     * @return
     */
    @Override
    public String notifyPayResult(Map<String, String> paramsMap) {
        try {
            //1.对提交所有参数进行业务校验
            //1.1 验签-防止数据在传输中被篡改以及"假通知"  //调用SDK验证签名
            boolean signVerified = AlipaySignature.rsaCheckV1(paramsMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);
            if (!signVerified) {
                return "failure";
            }
            //1.2 验证商家订单是否存在
            String outTradeNo = paramsMap.get("out_trade_no");
            OrderInfo orderInfo = orderFeignClient.getOrderInfoByOutradeNo(outTradeNo);
            if (orderInfo == null) {
                return "failure";
            }
            //1.3 验证支付宝交易实际金额跟本地交易记录中金额是否一致
            String totalAmount = paramsMap.get("total_amount");
            PaymentInfo paymentInfo = paymentInfoService.getPaymentInfo(outTradeNo, PaymentType.ALIPAY.name());
            if (paymentInfo == null || paymentInfo.getTotalAmount().compareTo(new BigDecimal(totalAmount)) != 0) {
                return "failure";
            }

            //1.4 验证app_id是否跟商家一致
            String appId = paramsMap.get("app_id");
            if (!AlipayConfig.alipay_app_id.equals(appId)) {
                return "failure";
            }


            // 2. 支付宝提交支付结果参数
            if ("TRADE_SUCCESS".equals(paramsMap.get("trade_status"))) {
                // 3.修改本地交易记录:支付状态-已支付
                paymentInfoService.paySuccess(paymentInfo, paramsMap);
                return "success";
            }


        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 退款
     *
     * @param orderId
     * @return
     */
    @Override
    public boolean refund(Long orderId) {
        try {
            //1.根据订单ID查询订单信息 只要订单支付成功才能退款
            OrderInfo orderInfo = orderFeignClient.getOrderInfo(orderId);
            //TODO 等支付后续业务完善以后,能够自动修改订单状态:已支付
            if (orderInfo != null && OrderStatus.PAID.name().equals(orderInfo.getOrderStatus())) {
                PaymentInfo paymentInfo = paymentInfoService.getPaymentInfo(orderInfo.getOutTradeNo(), PaymentType.ALIPAY.name());
                //判断支付状态只有已支付才能退款
                if (paymentInfo != null && PaymentStatus.PAID.name().equals(paymentInfo.getPaymentStatus())) {
                    //2.调用支付宝退款接口进行退款
                    AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
                    JSONObject bizContent = new JSONObject();
                    bizContent.put("trade_no", paymentInfo.getTradeNo());
                    bizContent.put("refund_amount", paymentInfo.getTotalAmount());
                    bizContent.put("out_request_no", "HZ01RF001");
                    bizContent.put("refund_reason", "不喜欢,跟商家协议一致退款!");
                    request.setBizContent(bizContent.toString());
                    AlipayTradeRefundResponse response = alipayClient.execute(request);
                    if (response.isSuccess()) {
                        //修改支付状态为关闭
                        paymentInfo.setPaymentStatus(PaymentStatus.CLOSED.name());
                        paymentInfoService.updateById(paymentInfo);
                        return true;
                    }
                }
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            log.error("[支付服务]退款异常:{}", e);
        }
        return false;
    }


    /**
     * 查询支付宝交易订单状态
     *
     * @param orderId
     * @return true:说明该订单等待支付
     */
    @Override
    public Boolean checkPaymentSatus(Long orderId) {
        try {
            //1.根据订单ID+支付方式查询本地交易记录
            PaymentInfo paymentInfo = paymentInfoService.getPaymentInfo(orderId, PaymentType.ALIPAY.name());
            if (paymentInfo != null) {
                //2.调用支付宝接口查询交易状态
                AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
                JSONObject bizContent = new JSONObject();
                bizContent.put("out_trade_no", paymentInfo.getOutTradeNo());
                request.setBizContent(bizContent.toString());
                AlipayTradeQueryResponse response = alipayClient.execute(request);
                if (response.isSuccess()) {
                    String tradeStatus = response.getTradeStatus();
                    if ("WAIT_BUYER_PAY".equals(tradeStatus)) {
                        return true;
                    }
                }
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return false;
    }


    /**
     * 关闭支付宝交易
     *
     * @param orderId
     * @return
     */
    @Override
    public void closeAliPay(Long orderId) {
        try {
            //1.根据订单ID+支付方式查询本地交易记录
            PaymentInfo paymentInfo = paymentInfoService.getPaymentInfo(orderId, PaymentType.ALIPAY.name());
            //2.调用支付宝接口关闭交易
            if (paymentInfo != null) {
                AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
                JSONObject bizContent = new JSONObject();
                bizContent.put("out_trade_no", paymentInfo.getOutTradeNo());
                request.setBizContent(bizContent.toString());
                AlipayTradeCloseResponse response = alipayClient.execute(request);
                if (response.isSuccess()) {
                    log.info("关闭支付宝订单成功:{}", orderId);
                } else {
                    log.error("关闭支付宝订单失败:{}", orderId);
                }
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            log.error("关闭支付宝订单失败:订单ID:{},异常信息:{}", orderId, e);
        }
    }
}
